/*
 * adcPacketHandler.h
 *
 * Created: 6/13/2013 3:01:16 AM
 *  Author: Tim
 */ 


#ifndef ADCPACKETHANDLER_H_
#define ADCPACKETHANDLER_H_

#include <avr/io.h>
#include "../status.h"
#include "../structs/adcPacketStructs.h"
#include "../CRC.h"
#include "../../features/tmr/tmr.h"
#include "../structs/msgHeaderDefs.h"
#include "../../features/adc/adc.h"
#include "../../communication/comPort.h"
#include "../../extFlash/flash.h"
#include "../structs//flashPacketStructs.h"

static inline status_t adcInitAsyncHandler(adcInitAsync_t *packet)
{
//	tmrAlloc_t intTmr;
	uint16_t frequency;
	
	if(daqAlloc.standAlone.daqStandAlone) return OPP_FAILED;//this function is not standalone type
	
	//check to see if any of the analog channels were previously allocated
//	if(daqAlloc.analogAlloc.analogInCh0Alloc == FEATURE_UTILIZED) return OPP_FAILED;
//	if(daqAlloc.analogAlloc.analogInCh1Alloc == FEATURE_UTILIZED) return OPP_FAILED;
//	if(daqAlloc.analogAlloc.analogInCh2Alloc == FEATURE_UTILIZED) return OPP_FAILED;
//	if(daqAlloc.analogAlloc.analogInCh3Alloc == FEATURE_UTILIZED) return OPP_FAILED;
	
	
	frequency = (packet->PARAM2.FREQH)<<8| packet->PARAM3.FREQL;
	
	

	if(daqAlloc.adc_int == TIMER_NULL)
	{
		//search for a free timer
		daqAlloc.adc_int = tmrCheckAvailability();
		if(daqAlloc.adc_int == TIMER_NULL) return OPP_FAILED;
	}
	//if the timer is free we must set it up for the prescribed frequency
	tmrSetupFreq(daqAlloc.adc_int, frequency);	
	
	// set the adc gains of the respective channels		
	adcSetGain(packet->PARAM1.ACHM,packet->PARAM1.GAIN);
	//allocate the adc channel interrupts appropriately
	if (packet->PARAM1.ACHM & ADC_CH0_bp)
	{
		daqAlloc.analogAlloc.analogInCh0Alloc = FEATURE_UTILIZED;
	//	daqAlloc.adcCh_int[0] = intTmr;
	}
	if (packet->PARAM1.ACHM & ADC_CH1_bp)
	{
		daqAlloc.analogAlloc.analogInCh1Alloc = FEATURE_UTILIZED;
	//	daqAlloc.adcCh_int[1] = intTmr;
	}
	if (packet->PARAM1.ACHM & ADC_CH2_bp)
	{
		daqAlloc.analogAlloc.analogInCh2Alloc = FEATURE_UTILIZED;
	//	daqAlloc.adcCh_int[2] = intTmr;
	}
	if (packet->PARAM1.ACHM & ADC_CH3_bp)
	{
		daqAlloc.analogAlloc.analogInCh3Alloc = FEATURE_UTILIZED;
	//	daqAlloc.adcCh_int[3] = intTmr;	
	}
	
	return OPP_SUCCESSFUL;
}

static inline status_t adcResultHandler()
{
	adcResult_t packet;
	
	int16_t	adcResult[4];

	packet.Header		= packetHeader;
	packet.msgHeader	= adcResult_mh;

		if(daqAlloc.analogAlloc.analogInCh0Alloc)	
		{
			adcResult[0] = filterData((int16_t *)adcCh0_data);
			packet.PARAM1.ADCRH0 =	adcResult[0]>>8; 
			packet.PARAM2.ADCRL0 =	0xFF & adcResult[0];
		}
		else
		{
			packet.PARAM1.ADCRH0 =	0;
			packet.PARAM2.ADCRL0 =	0;
		}										
		if(daqAlloc.analogAlloc.analogInCh1Alloc)	
		{
			adcResult[1] = filterData((int16_t *)adcCh1_data);
			packet.PARAM3.ADCRH1 =	adcResult[1]>>8;
			packet.PARAM4.ADCRL1 =	0xFF & adcResult[1];
		}
		else
		{
			packet.PARAM3.ADCRH1 =	0;
			packet.PARAM4.ADCRL1 =	0;
		}
		if(daqAlloc.analogAlloc.analogInCh2Alloc)	
		{
			adcResult[2] = filterData((int16_t *)adcCh2_data);
			packet.PARAM5.ADCRH2 =	adcResult[2]>>8;
			packet.PARAM6.ADCRL2 =	0xFF & adcResult[2];
		}
		else
		{
			packet.PARAM5.ADCRH2 =	0;
			packet.PARAM6.ADCRL2 =	0;
		}
		if(daqAlloc.analogAlloc.analogInCh3Alloc)	
		{
			adcResult[3] = filterData((int16_t *)adcCh3_data);
			packet.PARAM7.ADCRH3 =	adcResult[3]>>8;
			packet.PARAM8.ADCRL3 =	0xFF & adcResult[3];
		}
		else
		{
			packet.PARAM7.ADCRH3 =	0;
			packet.PARAM8.ADCRL3 =	0;
		}
	
	crcAppend(&packet,packetSizeLookup(adcResult_mh));
	comPortPut(&packet,packetSizeLookup(adcResult_mh));		
	return OPP_SUCCESSFUL;
}


static inline void adcFlashResultHandler()
{
	uint16_t temp;
	if(!(flash.curAddr & 0xFF))
	{
		flashDeSel();
		
		while(readStatusReg() & STSRG_BUSY_msk);
		
		writeEnable();
		
		flashSel();
		
		spiWrite(pageProgram_cmd);
		
		spiWrite((0xFF0000 & flash.curAddr)>>16);
		spiWrite((0x00FF00 & flash.curAddr)>>8);
		spiWrite(0x0000FF & flash.curAddr);
	}
	
	if(daqAlloc.analogAlloc.analogInCh0Alloc)
	{
		temp = filterData((int16_t *)adcCh0_data);
		spiWrite((0xFF00 & temp)>>8);
		spiWrite((0xFF & temp));
		
		flash.curAddr += 2;
		
		if(!(flash.curAddr & 0xFF))
		{
			flashDeSel();
			
			while(readStatusReg() & STSRG_BUSY_msk);
			
			writeEnable();
			
			flashSel();
			
			spiWrite(pageProgram_cmd);
			
			spiWrite((0xFF0000 & flash.curAddr)>>16);
			spiWrite((0x00FF00 & flash.curAddr)>>8);
			spiWrite(0x0000FF & flash.curAddr);
		}
	}
	if(daqAlloc.analogAlloc.analogInCh1Alloc)
	{
		temp = filterData((int16_t *)adcCh1_data);
		spiWrite((0xFF00 & temp)>>8);
		spiWrite((0xFF & temp));
		
		flash.curAddr += 2;
		
		if(!(flash.curAddr & 0xFF))
		{
			flashDeSel();
			
			while(readStatusReg() & STSRG_BUSY_msk);
			
			writeEnable();
			
			flashSel();
			
			spiWrite(pageProgram_cmd);
			
			spiWrite((0xFF0000 & flash.curAddr)>>16);
			spiWrite((0x00FF00 & flash.curAddr)>>8);
			spiWrite(0x0000FF & flash.curAddr);
		}
	}
	if(daqAlloc.analogAlloc.analogInCh2Alloc)
	{
		temp = filterData((int16_t *)adcCh2_data);
		spiWrite((0xFF00 & temp)>>8);
		spiWrite((0xFF & temp));
		
		flash.curAddr += 2;
		
		if(!(flash.curAddr & 0xFF))
		{
			flashDeSel();
			
			while(readStatusReg() & STSRG_BUSY_msk);
			
			writeEnable();
			
			flashSel();
			
			spiWrite(pageProgram_cmd);
			
			spiWrite((0xFF0000 & flash.curAddr)>>16);
			spiWrite((0x00FF00 & flash.curAddr)>>8);
			spiWrite(0x0000FF & flash.curAddr);
		}
	}
	if(daqAlloc.analogAlloc.analogInCh3Alloc)
	{
		temp = filterData((int16_t *)adcCh3_data);
		spiWrite((0xFF00 & temp)>>8);
		spiWrite((0xFF & temp));
		
		flash.curAddr += 2;
		
		if(!(flash.curAddr & 0xFF))
		{
			flashDeSel();
			
			while(readStatusReg() & STSRG_BUSY_msk);
			
			writeEnable();
			
			flashSel();
			
			spiWrite(pageProgram_cmd);
			
			spiWrite((0xFF0000 & flash.curAddr)>>16);
			spiWrite((0x00FF00 & flash.curAddr)>>8);
			spiWrite(0x0000FF & flash.curAddr);
		}
	}	
}


static inline status_t adcFlashInit(adcFlashInit_t *packet)
{
	tmrAlloc_t intTmr;
	uint16_t frequency;
	uint8_t numChannels;
	
	if(!(daqAlloc.standAlone.daqStandAlone)) return OPP_FAILED;
	if(daqAlloc.standAlone.aqState != AQ_INIT_STATE) return OPP_FAILED;
	
	frequency = (packet->PARAM2.FREQH)<<8| packet->PARAM3.FREQL;
	
	if(daqAlloc.adc_int == TIMER_NULL)
	{
		//search for a free timer
		daqAlloc.adc_int = tmrCheckAvailability();
		if(daqAlloc.adc_int == TIMER_NULL) return OPP_FAILED;
	}
	//if the timer is free we must set it up for the prescribed frequency
	tmrSetupFreq(daqAlloc.adc_int, frequency);
	
	// set the adc gains of the respective channels
	adcSetGain(packet->PARAM1.ACHM,packet->PARAM1.GAIN);
	
	flash.baseAddr = 0;
	flash.curAddr = 0;
	flash.numChannels = 0;
	flash.numSamples = (packet->PARAM4.SMPSH)<<8 | packet->PARAM5.SMPSL;
	
	daqAlloc.adc_int = intTmr;
	
	//allocate the adc channel interrupts appropriately
	if (packet->PARAM1.ACHM & ADC_CH0_bp)
	{
		daqAlloc.analogAlloc.analogInCh0Alloc = FEATURE_UTILIZED;
		
		flash.addrInc += 2;						//add two each time this function is called
		flash.numChannels++;
		
		flash.adcChAlloc.fCh0 = ADC_CH0_msk;
	}
	if (packet->PARAM1.ACHM & ADC_CH1_bp)
	{
		daqAlloc.analogAlloc.analogInCh1Alloc = FEATURE_UTILIZED;
		
		flash.addrInc += 2;						//add two each time this function is called
		flash.numChannels++;
		
		if(flash.numChannels == 2)			flash.adcChAlloc.fCh1 = ADC_CH1_msk;
		else								flash.adcChAlloc.fCh0 = ADC_CH1_msk;
		
	}
	if (packet->PARAM1.ACHM & ADC_CH2_bp)
	{
		daqAlloc.analogAlloc.analogInCh2Alloc = FEATURE_UTILIZED;
		
		flash.addrInc += 2;						//add two each time this function is called
		flash.numChannels++;
		
		if(flash.numChannels == 3)			flash.adcChAlloc.fCh2 = ADC_CH2_msk;
		else if(flash.numChannels == 2)		flash.adcChAlloc.fCh1 = ADC_CH2_msk;
		else								flash.adcChAlloc.fCh0 = ADC_CH2_msk;
		
	}
	if (packet->PARAM1.ACHM & ADC_CH3_bp)
	{
		daqAlloc.analogAlloc.analogInCh3Alloc = FEATURE_UTILIZED;
		
		flash.addrInc += 2;						//add two each time this function is called
		flash.numChannels++;
		
		if(flash.numChannels == 4)			flash.adcChAlloc.fCh3 = ADC_CH3_msk;
		else if(flash.numChannels == 4)		flash.adcChAlloc.fCh2 = ADC_CH3_msk;
		else if(flash.numChannels == 4)		flash.adcChAlloc.fCh1 = ADC_CH3_msk;
		else								flash.adcChAlloc.fCh0 = ADC_CH3_msk;
		
	}
	
	flash.finAddr = 2*flash.numSamples*flash.numChannels;
	
	return OPP_SUCCESSFUL;
}

static inline void  flashAdcInfo(uint8_t channel)
{
	flashAdcInfo_t packet;
	
	packet.Header = packetHeader;
	packet.msgHeader = flashAdcInfo_mh;
	
	//specifies which channel data will follow
	
	switch(channel)
	{
		case 0:
			packet.PARAM1.ACHN = flash.adcChAlloc.fCh0;
		break;
		case 1:
			packet.PARAM1.ACHN = flash.adcChAlloc.fCh1;
		break;
		case 2:
			packet.PARAM1.ACHN = flash.adcChAlloc.fCh2;
		break;
		case 3:
			packet.PARAM1.ACHN = flash.adcChAlloc.fCh3;
		break;
	}

	packet.PARAM2.SPDAH = flash.numSamples>>8;
	
	packet.PARAM3.SPDAL = 0xFF & (flash.numSamples);
	
	crcAppend(&packet,packetSizeLookup(flashAdcInfo_mh));
	comPortPut(&packet,packetSizeLookup(flashAdcInfo_mh));
	asm("nop");
}

static inline status_t adcBulkDataSend(uint8_t channel,flashAdcData_t *packet)
{
	
	uint16_t i;
	uint8_t achn;
	packet->Header = packetHeader;
	
	switch(channel)
	{
		case 0:
			achn = flash.adcChAlloc.fCh0;
		break;
		case 1:
			achn = flash.adcChAlloc.fCh1;
		break;
		case 2:
			achn = flash.adcChAlloc.fCh2;
		break;
		case 3:
			achn = flash.adcChAlloc.fCh3;
		break;
		
	}
	
	switch(achn)
	{
		case ADC_CH0_msk:
			packet->msgHeader = flashAdcData0_mh;
		break;
		case ADC_CH1_msk:
			packet->msgHeader = flashAdcData1_mh;
		break;
		case ADC_CH2_msk:
			packet->msgHeader = flashAdcData2_mh;
		break;
		case ADC_CH3_msk:
			packet->msgHeader = flashAdcData3_mh;
		break;
	}	
	
	crcAppend((flashAdcData_t *)packet,packetSizeLookup(flashAdcData0_mh));
	comPortPut((flashAdcData_t *)packet,packetSizeLookup(flashAdcData0_mh));
}

#endif /* ADCPACKETHANDLER_H_ */